package cn.tedu.charging.device.start;

import cn.tedu.charging.common.consts.RedisConstants;
import cn.tedu.charging.device.mapper.StationMapper;
import cn.tedu.charging.device.po.StationPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 实现redis数据预热的 容器bean对象
 */
@Component
@Slf4j
public class RedisWarmUp implements ApplicationRunner {
    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("redis预热程序开始运行");
        //1.读取数据库 charging.charging_station全表数据 需要持久层框架
        List<StationPO> pos = stationMapper.selectList(null);//没有查询条件 查询所有
        //2.组织一下放到redis中 放2个类型数据 一个geo 一个 string 需要redis客户端
        //在pos非空的时候 运行一下 缓存预热功能 保证缓存预热数据 幂等
        if (pos!=null&&pos.size()>0){
            for (StationPO po : pos) {
                saveStationCache(po);
            }
        }
        log.info("redis预热程序完成运行");
    }

    private void saveStationCache(StationPO po) {
        //1.把po 存储geo集合
        saveStationGeo(po);
        //2.把po 存储string缓存对象
        saveStationString(po);
    }

    private void saveStationString(StationPO po) {
        log.info("开始存储string缓存数据,当前value:{}",po);
        ValueOperations<String,StationPO> opsForValue = redisTemplate.opsForValue();
        //key值 使用的是站场的id value就是po对象
        //redis中使用string做缓存 key值绑定业务 但是要添加业务前缀
        opsForValue.set(RedisConstants.STATION_STRING_PREFIX+po.getId(),po);
    }

    private void saveStationGeo(StationPO po) {
        //多次调用 多次启动 是否会出现冗余的数据
        log.info("开始存储geo元素,当前元素值:{}",po.getId());
        //明确数据类型对应关系 String就是geo的集合key是字符串 Integer geo元素数据类型 Integer id
        GeoOperations<String,Integer> opsForGeo = redisTemplate.opsForGeo();
        Point point = new Point(po.getStationLng().doubleValue(), po.getStationLat().doubleValue());
        opsForGeo.add(RedisConstants.STATIONS_GEO,point,po.getId());
    }
}
